/***************************************************************************
 *   Copyright (C) 2006 by Grzegorz Latarowski                             *
 *   g.latarowski@gmail.com                                                *
 *                                                                         *
 *   Project: AutoStop (kodowa nazwa do zmiany)                            *
 *                                                                         *
 ***************************************************************************/
 
 
 

#include "sortfilterproxymodels.h"




// ===========================================================================
//                     GlobalSortFilterProxyModel
// ===========================================================================


// ------------------- GlobalSortFilterProxyModel() --------------------------
GlobalSortFilterProxyModel::GlobalSortFilterProxyModel(QObject * parent)
    :FilterModel(parent)
{
        // ustaw nazwę obiektu,
        // wykorzystywane będzie do rozpoznawania typów
    setObjectName("GlobalSortFilterProxyModel");
}
// ---------------------------------------------------------------------------


// ----------------------- acceptsRow() --------------------------------------
bool GlobalSortFilterProxyModel::acceptsRow(int sourceRow,
                                      const QModelIndex &sourceParent) const
{
    bool accept = false;
    QModelIndexList indexes;
    int columnCount;
    
        // nie uwzglęniaj ostaniej kolumny bo w niej jest plik 
    columnCount = sourceModel()->columnCount() - 1;
    for(int i = 0; i < columnCount; i++) {
        QModelIndex index = sourceModel()->index(sourceRow, i, sourceParent);
        indexes << index;
    }

    QModelIndex index;
    foreach(index, indexes) {
        accept = accept || sourceModel()->data(index)
                .toString().contains(filterRegExp());
    }
    
    return accept;
}
// ---------------------------------------------------------------------------


// ------------------------ filterAcceptsRow() -------------------------------
bool GlobalSortFilterProxyModel::filterAcceptsRow(int sourceRow,
        const QModelIndex &sourceParent) const
{
    return acceptsRow(sourceRow, sourceParent);
}
// ---------------------------------------------------------------------------


// ------------------------ operator << --------------------------------------
QDataStream & operator << (QDataStream & out, const GlobalSortFilterProxyModel * model)
{
        // W tym modelu zapisane musi być tylko filtrujące wyrażenie regularne
    QByteArray patternUtf8 = model->filterRegExp().pattern().toUtf8();
    out << patternUtf8;
    
    return out;
}
// ---------------------------------------------------------------------------


// ------------------------ operator >> --------------------------------------
QDataStream & operator >> (QDataStream & in, GlobalSortFilterProxyModel * model)
{
        // zaczytaj z pliku wyrażenie regularne
    QByteArray patternUtf8;
    in >> patternUtf8;
        // zapisz je do modelu
    QString pattern(patternUtf8);
    model->setFilterRegExp(QRegExp(pattern, Qt::CaseInsensitive));
    
    return in;
}
// ---------------------------------------------------------------------------






// ===========================================================================
//                          DateSortFilterProxyModel
// ===========================================================================


// ------------------------ DateSortFilterProxyModel() -----------------------
DateSortFilterProxyModel::DateSortFilterProxyModel(QObject * parent)
    :FilterModel(parent)
{    
        // ustaw nazwę obiektu,
        // wykorzystywane będzie do rozpoznawania typów
    setObjectName("DateSortFilterProxyModel");
    clear();
}
// ---------------------------------------------------------------------------


// ----------------------- setLowerBound() -----------------------------------
void DateSortFilterProxyModel::setLowerBound(const QDate lowerBound)
{
    _lowerBound = lowerBound;
        // odśwież widok 
    setFilterRegExp(QRegExp());
}
// ---------------------------------------------------------------------------


// ----------------------- setUpperBound() -----------------------------------
void DateSortFilterProxyModel::setUpperBound(const QDate upperBound)
{
    _upperBound = upperBound;
        // odśwież widok 
    setFilterRegExp(QRegExp());
}
// ---------------------------------------------------------------------------


// ----------------------------- dateInRange() -------------------------------
bool DateSortFilterProxyModel::dateInRange(const QDate date)const
{
    if((date >= _lowerBound) && (date <= _upperBound)) {
        return true;
    }
    return false;
}
// ---------------------------------------------------------------------------


// -------------------------- clearLowerBound() ------------------------------
void DateSortFilterProxyModel::clearLowerBound()
{
    setLowerBound(QDate::fromString("1900.01.01", "yyyy.MM.dd"));
        // odśwież widok 
    setFilterRegExp(QRegExp());
}
// ---------------------------------------------------------------------------


// -------------------------- clearUpperBound() ------------------------------
void DateSortFilterProxyModel::clearUpperBound()
{
    setUpperBound(QDate::fromString("3000.01.01", "yyyy.MM.dd"));
        // odśwież widok 
    setFilterRegExp(QRegExp());
}
// ---------------------------------------------------------------------------


// --------------------------------- clear() ----------------------------------
void DateSortFilterProxyModel::clear()
{
    clearLowerBound();
    clearUpperBound();
}
// ---------------------------------------------------------------------------


// ----------------------- acceptsRow() --------------------------------------
bool DateSortFilterProxyModel::acceptsRow(int sourceRow,
        const QModelIndex &sourceParent) const
{
    QModelIndex index;
    index = sourceModel()->index(sourceRow, filterKeyColumn(), sourceParent);
    QDate date = sourceModel()->data(index).toDate();
    
    if(date.isValid()) {
        return dateInRange(date);
    }
    return false;
}
// ---------------------------------------------------------------------------


// ------------------------ filterAcceptsRow() -------------------------------
bool DateSortFilterProxyModel::filterAcceptsRow(int sourceRow,
        const QModelIndex &sourceParent) const
{
    return acceptsRow(sourceRow, sourceParent);
}
// ---------------------------------------------------------------------------


// ------------------------ operator << --------------------------------------
QDataStream & operator << (QDataStream & out, const DateSortFilterProxyModel * model)
{
    qint32 column = model->filterKeyColumn();
    QDate lowerBound = model->lowerBound();
    QDate upperBound = model->upperBound();
    
    out << column << lowerBound << upperBound;
    
    return out;
}
// ---------------------------------------------------------------------------


// ------------------------ operator >> --------------------------------------
QDataStream & operator >> (QDataStream & in, DateSortFilterProxyModel * model)
{
    qint32 column;
    QDate lowerBound;
    QDate upperBound;
    in >> column >> lowerBound >> upperBound;
    
    model->setFilterKeyColumn(column);
    model->setLowerBound(lowerBound);
    model->setUpperBound(upperBound);
    
    return in;
}
// ---------------------------------------------------------------------------






// ===========================================================================
//                      RegExpSortFilterProxyModel
// ===========================================================================


// ------------------- RegExpSortFilterProxyModel() --------------------------
RegExpSortFilterProxyModel::RegExpSortFilterProxyModel(QObject * parent)
    :FilterModel(parent)
{    
        // ustaw nazwę obiektu,
        // wykorzystywane będzie do rozpoznawania typów
    setObjectName("RegExpSortFilterProxyModel");
}
// ---------------------------------------------------------------------------


// -------------------------- setFilterRegExp() ------------------------------
void RegExpSortFilterProxyModel::setFilterRegExp(const QRegExp & regExp)
{
    _regExp = regExp;
}
// ---------------------------------------------------------------------------


// ------------------------ acceptsRow() -------------------------------------
bool RegExpSortFilterProxyModel::acceptsRow(int sourceRow,
                                      const QModelIndex & sourceParent)const
{  
    bool accept = false;
       
    int column = filterKeyColumn();
    QModelIndex index;
    index = sourceModel()->index(sourceRow, column, sourceParent);
    accept = accept || sourceModel()->data(index)
            .toString().contains(_regExp);
    
    return accept;
}
// ---------------------------------------------------------------------------


// ---------------------- filterAcceptsRow() ---------------------------------
bool RegExpSortFilterProxyModel::filterAcceptsRow(int sourceRow,
            const QModelIndex & sourceParent)const
{    
    return acceptsRow(sourceRow, sourceParent);
}
// ---------------------------------------------------------------------------


// ------------------------ operator << --------------------------------------
QDataStream & operator << (QDataStream & out, const RegExpSortFilterProxyModel * model)
{
    qint32 column = model->filterKeyColumn();
    QString pattern = model->filterRegExp().pattern();
    QByteArray patternUtf8 = pattern.toUtf8();

    out << column << patternUtf8;
    
    return out;
}
// ---------------------------------------------------------------------------


// ------------------------ operator >> --------------------------------------
QDataStream & operator >> (QDataStream & in, RegExpSortFilterProxyModel * model)
{
    qint32 column;
    QByteArray patterUtf8;
    
    in >> column >> patterUtf8;
    
    model->setFilterKeyColumn(column);
    QString pattern(patterUtf8);
    model->setFilterRegExp(QRegExp(pattern, Qt::CaseInsensitive));
    
    return in;
}
// ---------------------------------------------------------------------------






// ===========================================================================
//                       DoubleSortFilterProxyModel
// ===========================================================================


// --------------------- DoubleSortFilterProxyModel() ------------------------
DoubleSortFilterProxyModel::DoubleSortFilterProxyModel(QObject * parent)
    :FilterModel(parent)
{    
        // ustaw nazwę obiektu,
        // wykorzystywane będzie do rozpoznawania typów
    setObjectName("DoubleSortFilterProxyModel");
    
    _lowerBound = -INFINITY;
    _upperBound = INFINITY;
}
// ---------------------------------------------------------------------------


// ------------------------ setLowerBound() ----------------------------------
void DoubleSortFilterProxyModel::setLowerBound(const double lowerBound)
{
    _lowerBound = lowerBound;
}
// ---------------------------------------------------------------------------


// ---------------------- setUpperBound() ------------------------------------
void DoubleSortFilterProxyModel::setUpperBound(const double upperBound)
{    
    _upperBound =upperBound;
}
// ---------------------------------------------------------------------------


// ------------------------- numberInRange() ---------------------------------
bool DoubleSortFilterProxyModel::numberInRange(const double number)const
{
    if((number >= _lowerBound) && (number <= _upperBound)) {
        return true;
    }
    return false;
}
// ---------------------------------------------------------------------------


// -------------------------- acceptsRow() -----------------------------------
bool DoubleSortFilterProxyModel::acceptsRow(int sourceRow,
        const QModelIndex & sourceParent)const
{
    bool accept = false;
    int column = filterKeyColumn();
    
    QModelIndex index;
    index = sourceModel()->index(sourceRow, column, sourceParent);
    bool ok;
    double number = sourceModel()->data(index).toDouble(&ok);
    
    if(ok) {
        accept = numberInRange(number);
    }
        
    return accept;
}
// ---------------------------------------------------------------------------


// ----------------------- filterAcceptsRow() --------------------------------
bool DoubleSortFilterProxyModel::filterAcceptsRow(int sourceRow,
        const QModelIndex & sourceParent)const
{
    return acceptsRow(sourceRow, sourceParent);
}
// ---------------------------------------------------------------------------


// ------------------------ operator << --------------------------------------
QDataStream & operator << (QDataStream & out, const DoubleSortFilterProxyModel * model)
{
    qint32 column = model->filterKeyColumn();
    qreal lowerBound = model->lowerBound();
    qreal upperBound = model->upperBound();
    
    out << column << lowerBound << upperBound;
    
    return out;
}
// ---------------------------------------------------------------------------


// ------------------------ operator >> --------------------------------------
QDataStream & operator >> (QDataStream & in, DoubleSortFilterProxyModel * model)
{
    qint32 column;
    qreal lowerBound;
    qreal upperBound;
    
    in >> column >> lowerBound >> upperBound;
    
    model->setFilterKeyColumn(column);
    model->setLowerBound(lowerBound);
    model->setUpperBound(upperBound);
    
    return in;
}
// ---------------------------------------------------------------------------






// ===========================================================================
//                       MultiTypeSortFilterProxyModel
// ===========================================================================


// --------------------- MultiTypeSortFilterProxyModel() ---------------------
MultiTypeSortFilterProxyModel::MultiTypeSortFilterProxyModel(QObject * parent)
    :FilterModel(parent)
{   
        // ustaw nazwę obiektu,
        // wykorzystywane będzie do rozpoznawania typów
    setObjectName("MultiTypeSortFilterProxyModel");
}
// ---------------------------------------------------------------------------


// ------------------ ~MultiTypeSortFilterProxyModel() -----------------------
MultiTypeSortFilterProxyModel::~MultiTypeSortFilterProxyModel()
{
    clear();
}
// ---------------------------------------------------------------------------


// ------------------------ setPatternModel() --------------------------------
void MultiTypeSortFilterProxyModel::setPatternModel(
        FilterModel *patternModel)
{
    clear();
    _patternModelList << patternModel;
    
    reset();
}
// ---------------------------------------------------------------------------


// ----------------------- setPatternModels() --------------------------------
void MultiTypeSortFilterProxyModel::setPatternModels(
        const QList<FilterModel *> patternModelList)
{
    clear();
    FilterModel *patternModel;
    foreach(patternModel, patternModelList) {
        _patternModelList << patternModel;
    }    
    
    reset();
}
// ---------------------------------------------------------------------------


// ------------------------- clear() -----------------------------------------
void MultiTypeSortFilterProxyModel::clear()
{    
    FilterModel *patternModel;
    foreach(patternModel, _patternModelList) {
        delete patternModel;
    }
    _patternModelList.clear();
}
// ---------------------------------------------------------------------------


// ------------------------ acceptsRow() -------------------------------------
bool MultiTypeSortFilterProxyModel::acceptsRow(int sourceRow,
        const QModelIndex &sourceParent)const
{          
    bool accept = false;
    
        // pierwsze filtrowanie, bez modeli bo po dodaniu sourceModel()
    if(_patternModelList.isEmpty()) return true;
    
    FilterModel *patternModel;
    foreach(patternModel, _patternModelList) {
        accept = accept || patternModel->acceptsRow(sourceRow, sourceParent);
        qDebug() << accept;
    }
    
    return accept;
}
// ---------------------------------------------------------------------------


// ------------------------ filterAcceptsRow() -------------------------------
bool MultiTypeSortFilterProxyModel::filterAcceptsRow(int sourceRow,
        const QModelIndex &sourceParent)const
{          
    return acceptsRow(sourceRow, sourceParent);
}
// ---------------------------------------------------------------------------


// ------------------------- setSourceModel() --------------------------------
void MultiTypeSortFilterProxyModel::setSourceModel(
        QAbstractItemModel * sourceModel)
{
        // ustaw sourceModel 
    FilterModel *patternModel;
    foreach(patternModel, _patternModelList) {
        patternModel->setSourceModel(sourceModel);
    }
    QAbstractProxyModel::setSourceModel(sourceModel);
    
    setFilterRegExp(QRegExp());
}
// ---------------------------------------------------------------------------


// ------------------------ operator << --------------------------------------
QDataStream & operator << (QDataStream & out, const MultiTypeSortFilterProxyModel * model)
{
    const QList<FilterModel *> patternModelList = model->patternModelList();
    quint32 modelsCount = patternModelList.size();

    // model zapisuje w formacie:
    // ilość modeli << modele(<< typ modelu(quint8) << model(proxyModel))

        // zapisz ilość modeli
    out << modelsCount;
        // zapisz każdy model
    FilterModel *filterModel;
    foreach(filterModel, patternModelList) {
        QString name = filterModel->objectName();
        if(name == "DateSortFilterProxyModel") {
            quint8 indicator = 1;
            out << indicator << (DateSortFilterProxyModel *)filterModel;
        }
        if(name == "RegExpSortFilterProxyModel") {
            quint8 indicator = 2;
            out << indicator << (RegExpSortFilterProxyModel *)filterModel;
        }
        if(name == "DoubleSortFilterProxyModel") {
            quint8 indicator = 4;
            out << indicator << (DoubleSortFilterProxyModel *)filterModel;
        }
    }

    qDebug() << "-------- multiModel";
    qDebug() << "         ZAPIS";
    qDebug() << "         size: " << modelsCount;
        
    return out;
}
// ---------------------------------------------------------------------------


// ------------------------ operator >> --------------------------------------
QDataStream & operator >> (QDataStream & in, MultiTypeSortFilterProxyModel * model)
{
    quint32 modelsCount;

        // zaczytaj ile jest modeli do wzięcia
    in >> modelsCount;

        // utwórz liste modeli
    QList<FilterModel *> patternModelList;
    
    for(quint32 i = 0; i < modelsCount; i++) {
            // jeśli nie ma danych w strumieniu to przerwij
        if(in.atEnd()) {
           break;
        }

            // zaczytaj typ modelu
        quint8 modelType;
        in >> modelType;
            // zaczytaj model
        DateSortFilterProxyModel *newDateModel;
        RegExpSortFilterProxyModel *newRegExpModel;
        DoubleSortFilterProxyModel *newDoubleModel;
        switch(modelType) {
            case 1:
                newDateModel = new DateSortFilterProxyModel;
                in >> newDateModel;
                patternModelList.append(newDateModel);
                break;
            case 2:
                newRegExpModel = new RegExpSortFilterProxyModel;
                in >> newRegExpModel;
                patternModelList.append(newRegExpModel);
                break;
            case 4:
                newDoubleModel = new DoubleSortFilterProxyModel;
                in >> newDoubleModel;
                patternModelList.append(newDoubleModel);
                break;
            default:
                break;
        } // switch
        
    } // for

        // zapisz wczytaną liste filtrów do modelu
    model->setPatternModels(patternModelList);
    

    qDebug() << "-------- multiModel";
    qDebug() << "         ODCZYT";
    qDebug() << "         size: " << modelsCount;
    
    return in;
}
// ---------------------------------------------------------------------------




// ===========================================================================
//                                Filter 
// ===========================================================================


// ----------------------------- Filter() ------------------------------------
Filter::Filter(QObject * parent, int type)
    : FilterModel(parent),
    QListWidgetItem((QListWidget *) parent, type)
{
        // ustaw nastawy defaultowe
    setText(QString());
    setIcon(QIcon(QString::fromUtf8(":/filter/images/filterIcons/tux.png")));
}
// ---------------------------------------------------------------------------
    
    
// ---------------------------- Filter() -------------------------------------
Filter::Filter(const QString & text, QObject * parent, int type)
    : FilterModel(parent),
    QListWidgetItem(text, (QListWidget *)parent, type)
{
        // ustaw nastawy defaultowe
    setText(QString());
    setIcon(QIcon(QString::fromUtf8(":/filter/images/filterIcons/tux.png")));
}
// ---------------------------------------------------------------------------


// ----------------------------- Filter() ------------------------------------
Filter::Filter(const QIcon & icon, const QString & text,
               QObject * parent, int type)
    : FilterModel(parent),
    QListWidgetItem(icon, text, (QListWidget *)parent, type)
{
        // ustaw nastawy defaultowe
    setText(QString());
    setIcon(QIcon(QString::fromUtf8(":/filter/images/filterIcons/tux.png")));
}
// ---------------------------------------------------------------------------


// ----------------------------- ~Filter() -----------------------------------
Filter::~Filter()
{
    clear();
}
// ---------------------------------------------------------------------------


// -------------------------- clearModelsList() ------------------------------
void Filter::clearModelsList()
{
    MultiTypeSortFilterProxyModel *model;
    foreach(model, _modelsList) {
        delete model;
    }
    _modelsList.clear();
        // ustaw nastawy defaultowe
    setText(QString());
    setIcon(QIcon(QString::fromUtf8(":/filter/images/filterIcons/tux.png")));
}
// ---------------------------------------------------------------------------


// ---------------------------- setSourceModel() -----------------------------
void Filter::setSourceModel(QAbstractItemModel * sourceModel)
{
            // ustaw sourceModel 
    MultiTypeSortFilterProxyModel *model;
    foreach(model, _modelsList) {
        model->setSourceModel(sourceModel);
    }
    QAbstractProxyModel::setSourceModel(sourceModel);
    
    setFilterRegExp(QRegExp());
}
// ---------------------------------------------------------------------------


// ----------------------------- acceptsRow() --------------------------------
bool Filter::acceptsRow(int sourceRow, const QModelIndex & sourceParent)const
{
    bool accept = true;
    
        // pierwsze filtrowanie, bez modeli bo po dodaniu sourceModel()
    if(_modelsList.isEmpty()) return true;
    
    MultiTypeSortFilterProxyModel *model;
    foreach(model, _modelsList) {
        accept = accept && model->acceptsRow(sourceRow, sourceParent);
    }
    
    return accept;
}
// ---------------------------------------------------------------------------


// ---------------------------- filterAcceptsRow() ---------------------------
bool Filter::filterAcceptsRow(int sourceRow,
                              const QModelIndex & sourceParent)const
{
    return acceptsRow(sourceRow, sourceParent);
}
// ---------------------------------------------------------------------------


// ------------------------- addModel() --------------------------------------
void Filter::addModel(MultiTypeSortFilterProxyModel *model)
{
        // jeśli lista jest pusta to ustaw tylko jeden model
    if(_modelsList.isEmpty()) {
        model->setSourceModel(sourceModel());
        _modelsList.append(model);
    } else {
        // na liście są już modele więc ustaw sourceModel
        // dla dodawanego na ostatni z listy
        
        model->setSourceModel(_modelsList.last()->sourceModel());
        _modelsList.append(model);
    }

    qDebug() << "Filter::addModel modelSize: " << model->patternModelListSize();
}
// ---------------------------------------------------------------------------


// -------------------------- operator >> ------------------------------------
QDataStream & operator >> (QDataStream & in, Filter *filter)
{
        // wyczyść modele w zapisywanym filtrze
    filter->clear();
        // zaczytaj ilość modeli
    quint32 modelsCount;
    in >> modelsCount;
        // zaczytaj nazwe filtra
    QByteArray name;
    in >> name;
    filter->setText(QString(name));
        // zaczytaj ikonę filtra
    QPixmap pixmap;
    in >> pixmap;
    filter->setIcon(QIcon(pixmap));

    for(quint32 i = 0; i < modelsCount; i++) {
        MultiTypeSortFilterProxyModel *model = new MultiTypeSortFilterProxyModel;
        in >> model;
        filter->addModel(model);
    }

    qDebug() << "===========================================";
    qDebug() << "ODCZYT";
    qDebug() << "size: " << filter->modelsCount();
    qDebug() << "name: " << qPrintable(filter->text());
    qDebug() << "icon size: " << filter->icon().actualSize(QSize(64, 64));
        
    
    return in;
}
// ---------------------------------------------------------------------------


// --------------------------- operator << -----------------------------------
QDataStream & operator << (QDataStream & out, const Filter *filter)
{
        // zapisz ilość modeli w filtrze
    quint32 modelsCount = filter->modelsCount();
    out << modelsCount;
    
    qDebug() << "===========================================";
    qDebug() << "ZAPIS";
    qDebug() << "modelsCount: " << modelsCount;
        // zapisz nazwę filtra
    QByteArray name = filter->text().toUtf8();
    out << name;
    qDebug() << "name: " << name;
        // zapisz ikonę filtra
    qDebug() << "icon is NULL: " << filter->icon().isNull();
    qDebug() << "icon size: " << filter->icon().actualSize(QSize(64, 64));
    QPixmap pixmap = filter->icon().pixmap(QSize(64, 64));
    out << pixmap;
        // zapisz wszystkie modele
    MultiTypeSortFilterProxyModel *model;
    QList<MultiTypeSortFilterProxyModel *> modelsList = filter->modelsList();
    qDebug() << "list size: " << modelsList.size();
    foreach(model, modelsList) {
        out << model;
        qDebug() << "model: " << model;
    }
    
    return out;
}
// ---------------------------------------------------------------------------











